home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #2
/
Monster Media No. 2 (Monster Media)(1994).ISO
/
prog_gen
/
gcoope10.zip
/
GENLIST.C
< prev
next >
Wrap
Text File
|
1994-07-22
|
6KB
|
219 lines
/*
generic function list manager for GCOOPE version 1.0
by Brian Lee Price
Released as Public Domain July, 1994.
These routines handle GCOOPE's virtual/overloaded/polymorphic/
generic functions, all generic function dispatching uses the
lists set up and accessed through them.
Please examine gcstruct.h and listmgr.c prior to any serious
review of the source code presented here.
*/
#define __GENERICS__
#include "gcstruct.h"
#include <stdlib.h>
#include <mem.h>
/*
AVAILABLE FOR EXTERNAL USE:
Tag compare routine is designed for use with qsort and bsearch.
*/
int tagCmp(const void * ptrA, const void * ptrB)
{
return *((const tag *) ptrA)-*((const tag *) ptrB);
}
/*
FOR KERNAL USE ONLY!
usage:
newGenericFunctionIndex = addGeneric(default_method);
The dynList polyTable is actually an unordered list of ordered
lists, the generic function index is used to find the appropriate
ordered list containing the method dispatching info for that
generic function. On a failure this routine returns the value
MAX_GEN.
*/
generic addGeneric(method defMthd)
{
int x;
genEntry * genList;
if((x=addItem(&genTable, sizeof(genEntry)))<0) return MAX_GEN;
genList=genTable.listPtr;
genList+=x;
genList->elemSize=sizeof(genMethod);
genList->defMthd=defMthd;
return x;
}
/*
FOR KERNEL USE ONLY!
usage:
genItemElemSize=rmvVirtFunc(generic_type_generic_function_to_remove);
Here you find the common way of accessing a generic function, that
method is by the tag variable of type generic for the generic function.
This value is actually an index to genTable.
Note that this routine uses the return value setup as in the listmgr
function rmvItem, NOT the FUNCOKAY/FUNCFAIL value.
*/
int rmvGeneric(generic genFunc)
{
genEntry * genList;
if(genFunc>=genTable.maxElems || genFunc<0) return -1;
genList=genTable.listPtr;
genList+=genFunc;
if(genList->listPtr!=NULL)
s_free(genList->listPtr);
return rmvItem(&genTable, genFunc);
}
/*
FOR KERNEL USE ONLY.
usage:
genericFunctionEntryPtr=getMthd(generic_type_function,
class_tag_value_of_class_for_method_lookup);
This is the core routine for generic function dispatching,
given a generic function index value and a class tag value
(see objList.c for an explanation of class tags), this routine
will return a pointer to the generic list entry in the generic
list indexed by the generic function index value and looked up
via. bsearch with the class tag value used as the key. The
reason this routine does not just return the method pointer is
because some possible future enhancements could result in
additional information being stored in the generic list entry
structure.
*/
genMethod * getMthd(generic genFunc, int clsTag)
{
genEntry * genList;
if(genFunc>=genTable.maxElems || genFunc<0) return NULL;
genList=genTable.listPtr;
genList+=genFunc;
return bsearch(&clsTag,genList->listPtr,genList->firstFree,
sizeof(genMethod), tagCmp);
/*
Note that this function will return NULL on an error, the return
value of this function ABSOLUTELY MUST be validated or you are
guaranteed a spectacular program crash!
*/
}
/*
FOR KERNEL USE ONLY!
usage:
functionStatus=addMethod(generic_type_function,
type_method_method_pointer, method_class_tag_value,
child_class_tag_value);
Things are getting tricky, this routine installs a method given
by addMthd into the generic function list given by genFunc,
for the calling class given by clsTag. The value owner may
(or may not) be used by the function dispatcher, however it
is the class tag of the actual owning class of the method while
clsTag is (possibly) an class which inherits the method.
An easy to miss feature of this routine is that it will
overwrite a previous entry for the same generic function and
calling class. The reason is that methods are installed in the
reverse order of inheritance, thus it is possible for an
inheriting class to replace a method defined in a superClass.
This function uses the (standard ???) FUNCFAIL/FUNCOKAY
return values.
*/
stat addMethod(generic genFunc, method addMthd,
tag clsTag, tag owner)
{
int x;
genEntry * genList;
genMethod * methPtr;
if(addMthd==(method) NULL || genFunc>=genTable.maxElems || genFunc<0)
return FUNCFAIL;
genList=genTable.listPtr;
genList+=genFunc;
if(NULL!=(methPtr=bsearch(&clsTag, genList->listPtr, genList->firstFree,
sizeof(genMethod), tagCmp)))
{
methPtr->instMethod=addMthd;
methPtr->owner=owner;
return FUNCOKAY;
}
if((x=addItem(genList, sizeof(genMethod)))<0) return FUNCFAIL;
methPtr=genList->listPtr;
methPtr+=x;
methPtr->class=clsTag;
methPtr->owner=owner;
methPtr->instMethod=addMthd;
qsort(genList->listPtr, genList->firstFree, sizeof(genMethod), tagCmp);
return FUNCOKAY;
}
/*
FOR KERNEL USE ONLY.
usage:
functionStatus=rmvMethod(type_generic_function, calling_class_tag,
owning_class_tag);
This function will remove a method from a generic function's list.
It is designed to be called during class removal. It returns the
semi-standard FUNCFAIL/FUNCOKAY status value.
*/
stat rmvMethod(generic genFunc, tag clsTag)
{
genEntry * genList;
genMethod * methPtr;
stat retVal=FUNCFAIL;
if(genFunc>=genTable.maxElems || genFunc<0) goto end;
genList=genTable.listPtr;
genList+=genFunc;
if(genList->listPtr==NULL) goto end;
if((methPtr=bsearch(&clsTag,genList->listPtr,genList->firstFree,
sizeof(genMethod), tagCmp))==NULL) goto end;
memset(methPtr,0x,sizeof(genMethod));
genList->firstFree=(int) ((methPtr - genList->listPtr)/genList->elemSize);
compactList(genList, TRUE);
retVal=FUNCOKAY;
end:
return retVal;
}